#ifndef PRODUCTION_H
#define PRODUCTION_H

#include <vector>
#include <list>
#include <set>
#include <string>
#include <cassert>
#include "GrammarSymbol.h"


// Definition of Production class
class Production {
private:
    static std::vector<Production> production_vct;
    static int epsilo_index;

    int production_id;
    std::list<GrammarSymbol*> body_symbol_table;
    std::set<TerminalSymbol*> first_set;

    Production(int id, std::list<GrammarSymbol*> body_symbols);

    std::string get_info();

    static void calculate_first_one(Production& production);
    static void calculate_follow_one(Production& production);

public:
    static bool follow_flag; //当计算完follow，这个改为true
    static const std::vector<Production>& get_production_vct();
    static PRO_ID insert_production(std::list<GrammarSymbol*> body_symbols);

    template<typename... Args>
    static PRO_ID insert_production(GrammarSymbol* first_symbol, Args... args);

    static void remove_production(int index);
    static PRO_ID get_epsilo_production_id();
    static Production* get_production(PRO_ID id);
    static std::list<GrammarSymbol*> get_production_body_symbol_table(PRO_ID id);
    static std::set<TerminalSymbol *> get_production_first_set(PRO_ID id);
    static std::string get_info(PRO_ID id);
    static NonTerminalSymbol* get_left_most_nonterminal(PRO_ID id);
    static void calcu_first(PRO_ID id);
    static void calcu_follow();

};


template<typename... Args>
PRO_ID Production::insert_production(GrammarSymbol* first_symbol, Args... args) {
    std::list<GrammarSymbol*> body_symbols;
    body_symbols.push_back(first_symbol);

    (body_symbols.push_back(args), ...);

    production_vct.push_back(Production(production_vct.size(), body_symbols));
    return production_vct.size() - 1;
}

extern PRO_ID epsilo_production_id;


#endif // PRODUCTION_H
